package br.ufc.customJDBC;


import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.DriverPropertyInfo;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;

import net.sf.jsqlparser.JSQLParserException;
import br.ufc.custom.multiHistogram.MultiHistogram;
import br.ufc.customJDBC.Workaround.TempConnection;
import br.ufc.customJDBC.csv.CSVLog;
import br.ufc.customJDBC.routing.BroadcastRouter;
import br.ufc.customJDBC.routing.CircularQueueRouter;
import br.ufc.customJDBC.routing.HashRouter;
import br.ufc.customJDBC.routing.HistogramRouter;
import br.ufc.customJDBC.routing.MultiHistogramRouter;
import br.ufc.customJDBC.routing.ProvisioningRouter;
import br.ufc.customJDBC.routing.RandomProvisioningRouter;
import br.ufc.customJDBC.routing.Router;
import br.ufc.customJDBC.routing.VariableCircularQueueRouter;
import br.ufc.histogram.Histogram;
import br.ufc.histogram.TaskScheduler;
import br.ufc.parser.Value;
import br.ufc.util.CsvLoader;


public class CustomDriver implements java.sql.Driver{
	static private CustomDriver singleton;
	static private org.postgresql.Driver postgresDriver;
	static public final String basePath = "CloudJDBC/";
	private static CSVLog csv;
	private static ResourceAddition resourceAddition;
	private static boolean connected = false;
	private static List<Connection> connectionPool = new ArrayList<Connection>();
	private static List<CustomConnection> customConnectionPool = new ArrayList<CustomConnection>();
	private static Connection connection = null;

	static {
		System.out.println("Static do customDriver");
		singleton = new CustomDriver();
		try {
			DriverManager.registerDriver(singleton);
		} catch (SQLException e) {
			throw new RuntimeException("Unable to register the JDBC driver!");
		}
		postgresDriver = new org.postgresql.Driver();
		System.out.println("Driver inicializado!");
		File file = new File(CustomDriver.basePath+"log/log"+System.nanoTime()+".csv");
		csv = new CSVLog(file.getAbsolutePath());
	}

	@Override
	public Connection connect(String url, Properties info) {
		System.out.println("Conectando!");
		if (!url.startsWith("jdbc:customJDBC:")) {
			return null;
		}		
//		CsvLoader csvLoader = new CsvLoader("/home/victor/oltpbench/CloudJDBC/log/ycsb_e_real.csv");						
//		MultiHistogram mh = new MultiHistogram(csvLoader.load(1000), customConnectionPool.size(), 3);
//		setRouter(new MultiHistogramRouter(customConnectionPool, mh, csv));
//		setRouter(new HashRouter(customConnectionPool, csv));
//		setRouter(new BroadCcastRouter(customConnectionPool, csv));
//		setRouter(new VariableCircularQueueRouter(customConnectionPool, csv, 1));
//		startThread();
		return setRouter(url);
	}
	
	public static TempConnection setRouter(String url) {
		String[] S = url.split(":");
		BufferedReader br = null;
		try {
			br = new BufferedReader(new FileReader(S[2]));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			System.exit(-1);
		}
		if(!connected){
			String s;
			try {
				while((s = br.readLine()) != null){
					String[] parts = s.split("\\s");				
					System.out.println(parts[0]);
					Properties props = new Properties();
					props.setProperty("user",parts[1]);
					props.setProperty("password",parts[2]);
					connection = postgresDriver.connect(parts[0], props);
	
					String[] parts1 = parts[0].split(":");
					String ip = parts1[2].replaceFirst("//", "");
	
					CustomConnection con = new CustomConnection(connection, parts[0], csv);
					connectionPool.add(con);
					customConnectionPool.add(con);
				}
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			connected = true;
		}
//		Router router = new CircularQueueRouter(customConnectionPool, csv);
		Router router = RandomProvisioningRouter.getInstance(customConnectionPool, 25000000, 5000000, csv);
		
//		List <Integer> history = loadHistory(CustomDriver.basePath+"history.h");
//		Router router = ProvisioningRouter.getInstance(customConnectionPool, 1000000, 1000000, csv, history);
		
		TempConnection tempConnection = new TempConnection(connection, connectionPool, router);
		return tempConnection;
	}
	
//	private synchronized void startThread(){
//		if(resourceAddition == null){
//			ResourceAddition ra = new ResourceAddition(router);
//			ra.start();
//		}
//	}
	
	public static List<Integer> loadHistory(String filename){
		List<Integer> history = new ArrayList<Integer>();
		BufferedReader br;
		String line = null;
		try {
			br = new BufferedReader(new FileReader(filename));
			line = br.readLine();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
		String[] split = line.split(" ");
		for(String s : split){
			history.add(Integer.parseInt(s));
		}		
		return history;
	}


	public static void main(String args[]){
//		CsvLoader csvLoader = new CsvLoader("csvexamples/ycsb-ReadRecord.csv");		
//		MultiHistogram mh = new MultiHistogram(csvLoader.load(1000), 3, 3);
//		System.out.println(mh.getPartitionsForStatement("SELECT MAX(ycsb_key) FROM \"USERTABLE\""));
		//new CustomInsert("insert into table_name (col1 ,col2) values (val1 , val2) ");
//		PrintWriter writer = null;
//		try {
//			writer = new PrintWriter("tmp/node0.sql", "UTF-8");
//		} catch (FileNotFoundException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		} catch (UnsupportedEncodingException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}		
//		writer.print("DELETE FROM \"USERTABLE\" WHERE ");
//		for(Double d = 0.0; d <= 1999999; d += 1.0){
//			if((new Value(d).hashCode() % 3) != 0){
//				writer.print("(ycsb_key == " + d.intValue() + ") OR ");
//			}
//				System.out.print("(ycsb_key == " + d.intValue() + ") OR ");
//		}
//		writer.close();
//		Value v = new Value(10.0);
//		System.out.println(v.hashCode());
	}

	@Override
	public boolean acceptsURL(String url) throws SQLException {
		// TODO Auto-generated method stub
		System.out.println("AcceptsURL");
		return url != null && url.startsWith("jdbc:customJDBC:");
	}

	@Override
	public DriverPropertyInfo[] getPropertyInfo(String url, Properties info)
			throws SQLException {
		// TODO Auto-generated method stub
		return postgresDriver.getPropertyInfo(url, info);
	}

	@Override
	public int getMajorVersion() {
		// TODO Auto-generated method stub
		return postgresDriver.getMajorVersion();
	}

	@Override
	public int getMinorVersion() {
		// TODO Auto-generated method stub
		return postgresDriver.getMinorVersion();
	}

	@Override
	public boolean jdbcCompliant() {
		// TODO Auto-generated method stub
		return postgresDriver.jdbcCompliant();
	}

	@Override
	public Logger getParentLogger() throws SQLFeatureNotSupportedException {
		// TODO Auto-generated method stub
		throw new UnsupportedOperationException("Not supported yet.");
	}
}

class ResourceAddition extends Thread{
	private Router router;
	public ResourceAddition(Router router){
		this.router = router;
	}
	public void run() {
		try {
			sleep(30000);
			System.out.println("Adicionou");
			((VariableCircularQueueRouter)router).addServer(1);
			sleep(10000);
			System.out.println("Adicionou");
			((VariableCircularQueueRouter)router).addServer(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}